package com.bwton.msx.ccb.ui;

import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.text.TextUtils;
import android.util.Base64;

import com.bwton.msx.ccb.Constants;
import com.bwton.msx.ccb.R;
import com.bwton.msx.ccb.utils.FileUtil;
import com.bwton.msx.ccb.utils.PreferenceUtil;
import com.bwton.msx.ccb.utils.SourceManager;
import com.bwton.msx.ccb.utils.Toaster;
import com.sensetime.ssidmobile.sdk.liveness.OnOnlineDataSourceListener;
import com.sensetime.ssidmobile.sdk.liveness.OnlineCallback;
import com.sensetime.ssidmobile.sdk.liveness.STLiveness;
import com.sensetime.ssidmobile.sdk.liveness.constants.STDetectorMode;
import com.sensetime.ssidmobile.sdk.liveness.constants.STLivenessStage;
import com.sensetime.ssidmobile.sdk.liveness.constants.STResultCode;
import com.sensetime.ssidmobile.sdk.liveness.constants.STPixelFormat;
import com.sensetime.ssidmobile.sdk.liveness.model.STResult;
import com.sensetime.ssidmobile.sdk.liveness.model.STResultImage;
import com.sensetime.ssidmobile.sdk.liveness.model.STSignedData;
import com.sensetime.ssidmobile.sdk.liveness.model.config.DefakeConfig;
import com.sensetime.ssidmobile.sdk.liveness.model.config.DetectorConfig;
import com.sensetime.ssidmobile.sdk.liveness.model.config.ModelsConfig;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;


public class SilentActivity extends LivenessActivity {

    public static void start(Context context) {
        context.startActivity(new Intent(context, SilentActivity.class));
    }


    @Override
    protected DetectorConfig createDetectorConfig() {
        Context context = this;
        String destFilePath = context.getCacheDir().getAbsolutePath() + "/models/";
        return new DetectorConfig.Builder()
                .setLicenseContent(FileUtil.getLicenseContent(context, Constants.FACE_LICENSE_FILE_NAME)) //加载 license内容
                .setModelsConfig(new ModelsConfig.Builder()
                        .setHunterModelPath(FileUtil.copyAssetsToFile(context, Constants.MODEL_HUNTER_FILE_NAME, destFilePath)) // 具体模型路径
                        .setAlignModelPath(FileUtil.copyAssetsToFile(context, Constants.MODEL_ALIGN_FILE_NAME, destFilePath))
                        .setAugustModelPath(FileUtil.copyAssetsToFile(context, Constants.MODEL_AUGUST_FILE_NAME, destFilePath))
                        .setEyeStateModelPath(FileUtil.copyAssetsToFile(context, Constants.MODEL_EYESTATE_FILE_NAME, destFilePath))
                        .setHeadPoseModelPath(FileUtil.copyAssetsToFile(context, Constants.MODEL_HEADPOSE_FILE_NAME, destFilePath))
                        .setLivenessModelPath(FileUtil.copyAssetsToFile(context, Constants.MODEL_LIVENESS_FILE_NAME, destFilePath))
                        .setPageantModelPath(FileUtil.copyAssetsToFile(context, Constants.MODEL_PAGEANT_FILE_NAME, destFilePath))
                        .build())
                .build();
    }

    @Override
    protected void init(DetectorConfig detectorConfig) {
        mSTLiveness = new STLiveness();
        mSTLiveness.init(
                getApplicationContext(),
                detectorConfig,
                this
        );
    }

    @Override
    protected void onDestroy() {
        if (mSTLiveness != null) {
            mSTLiveness.destroy();
        }
        super.onDestroy();
    }

    @Override
    public void onInit(STResult result) {
        if (result.code == STResultCode.OK) {
            mSTLiveness.setQualityConfig(PreferenceUtil.getQualityConfig());
            mSTLiveness.setLivenessConfig(PreferenceUtil.qetLivenessConfig());
            mSTLiveness.setSilentConfig(PreferenceUtil.qetSilentConfig());
            DefakeConfig defakeConfig = PreferenceUtil.getDefakeConfig();
            if (defakeConfig.isDefake) {
                mSTLiveness.setDefakeConfig(defakeConfig);
                mSTLiveness.setOnlineDataSource(new OnOnlineDataSourceListener() {
                    @Override
                    public void uploadData(byte[] bytes, final OnlineCallback onlineCallback) {
                        // defake接口地址
                        String defakeUrl = "";
                        if (TextUtils.isEmpty(defakeUrl)){
                            Toaster.show("defake服务未配置，无法使用该功能");
                        }else {
                            SourceManager.getInstance().postReaction(defakeUrl, bytes)
                                    .map(new Function<String, byte[]>() {
                                        @Override
                                        public byte[] apply(String defakeBase64) throws Exception {
                                            return Base64.decode(defakeBase64, Base64.NO_WRAP);
                                        }
                                    })
                                    .subscribeOn(Schedulers.io())
                                    .observeOn(AndroidSchedulers.mainThread())
                                    .subscribe(new Consumer<byte[]>() {
                                        @Override
                                        public void accept(byte[] bytes) throws Exception {
                                            onlineCallback.call(bytes);
                                        }
                                    }, new Consumer<Throwable>() {
                                        @Override
                                        public void accept(Throwable throwable) throws Exception {
                                            throwable.printStackTrace();
                                        }
                                    });
                        }
                    }
                });
            }
            mSTLiveness.setDetectorMode(STDetectorMode.SILENT);
            mFaceOverlayView.post(new Runnable() {
                @Override
                public void run() {
                    mTargetRect = mCameraPreview.convertViewRectToCameraPreview(mFaceOverlayView.getMaskBounds());
                    // 配置取景框
                    mSTLiveness.setTargetRect(mTargetRect);
                    // 启动扫描器
                    mSTLiveness.start();
                    // 准备接受帧
                    isInput = true;
                }
            });
        } else {
            // 初始化异常
            isInput = false;
            Toaster.show("初始化异常，异常码:" + result);
            onFailure(result, null,null,null,null);
        }
    }

    @Override
    public void onUpdateStage(int stage) {
        switch (stage) {
            case STLivenessStage.DEFAKE:
                changeHint(R.string.status_check);
                break;
            case STLivenessStage.SYSTEM_ERROR:
                Toaster.show(getString(R.string.error_system));
                break;
        }
    }

    @Override
    public void onResult(STResult stResult, STResultImage originalResultImage, STResultImage cropResultImage, STResultImage[] stageResultImages, STSignedData signedData) {
        if (stResult.code == STResultCode.OK){
            onSuccess(originalResultImage,cropResultImage,stageResultImages,signedData);
        }else {
            onFailure(stResult, originalResultImage, cropResultImage, stageResultImages,signedData);
        }
    }

    public void onFailure(final STResult stResult, STResultImage originalResultImage, STResultImage cropResultImage, STResultImage[] stageResultImages, STSignedData signedData) {
        if (stResult.code == STResultCode.FACE_LOST) {
            if (isFoundFace) {
                restartDetector();
            } else {
                changeHint(R.string.error_status_out_bound);
                restartLiveness();
            }
            return;
        }
        ResultActivity.Result result = saveResult(originalResultImage, cropResultImage, stageResultImages,signedData);
        result.resultCode = stResult.code;
        result.resultMessage = stResult.message;
        startResultActivity(result);
    }


    public void onSuccess(STResultImage originalResultImage, STResultImage cropResultImage, STResultImage[] stageResultImages, STSignedData signedData) {
        ResultActivity.Result result = saveResult(originalResultImage, cropResultImage, stageResultImages,signedData);
        result.resultCode = STResultCode.OK;
        startResultActivity(result);
    }

    @Override
    protected void startResultActivity(ResultActivity.Result result) {
        isInput = false;
        ResultActivity.start(SilentActivity.this, result);
        finish();
    }

    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        if (mSTLiveness != null && isInput) {
            Camera.Size previewSize = camera.getParameters().getPreviewSize();
            mSTLiveness.input(bytes, STPixelFormat.NV21, previewSize.width, previewSize.height, mFaceOrientation);
        }
    }

    @Override
    protected void showDetectingHint() {
        changeHint(R.string.error_status_normal);
    }

    @Override
    protected void restartLiveness() {
        if (mSTLiveness != null) {
            mSTLiveness.restart();
        }
    }
}
